package com.advance.springcloud.distributeredislualock9032.controller;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * @program: spring-cloud-demo-advance
 * @description: 商品控制器，模仿预减库存
 * @author: advance
 * @create: 2021-03-22 14:25
 **/
@RestController
@Slf4j
public class GoodsController {

    @Autowired
    private RedisTemplate redisTemplate;

    private final static String STOCK_KEY = "stock";
    private final static String PRODUCT_SECKILL_KEY = "{SECKILL}:PRODUCT::100647::USERID::120";
    private final static String SECKILL_LOCK_KEY = "SECKILL_KEY";

    @PostConstruct
    public void initData() {
        redisTemplate.opsForValue().set(STOCK_KEY, 200);
    }

    @RequestMapping("/reduce")
    public String reduceStock() {
        //获取redis中的库存
        Integer stock = (Integer) redisTemplate.opsForValue().get(STOCK_KEY);

        log.info("剩余库存---------->"+stock);

        // 如果没有库存，返回
        if (stock <= 0) {
            log.info("-----------秒杀结束------------");
            return "秒杀结束！";
        }

        stock = stock - 1;

        redisTemplate.opsForValue().set(STOCK_KEY, stock);

        return "end";
    }

    /**
     * 添加分布式锁
     * 使用setnx实现
     * 1、优化：加锁时记得要给锁加上过期时间，防止死锁
     * 2、锁删除的时候需要判断是否为自己的锁，防止被其他线程提前删除从而导致锁失效
     * @return
     */
    @RequestMapping("/dislock/reduce")
    public String reduceStockWithDisLock() {

        //添加分布式锁
        boolean isCanLock = redisTemplate.opsForValue().setIfAbsent(SECKILL_LOCK_KEY, PRODUCT_SECKILL_KEY, 10, TimeUnit.SECONDS);

        //没拿到锁就给出提示
        if(!isCanLock){
            return "很遗憾，没有抢到！";
        }

        try{
            //获取redis中的库存
            Integer stock = (Integer) redisTemplate.opsForValue().get(STOCK_KEY);

            // 如果没有库存，返回
            if (stock > 0) {
                int keepStock = stock - 1;

                redisTemplate.opsForValue().set(STOCK_KEY, keepStock);
                System.out.println("商品扣减成功，剩余商品："+keepStock);
            }else{
                log.info("-----------秒杀结束------------");
                return "秒杀结束！";
            }

        }finally {
            redisTemplate.delete(SECKILL_LOCK_KEY);
        }

        return "end";
    }

}
